﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace System.Collections.Data
{
    /// <summary>
    /// A category provider assigns items to categories and details
    /// the full category list for a set of items.
    /// </summary>
    public interface ICategoryProvider
    {
        /// <summary>
        /// Gets the category for the given items
        /// </summary>
        object GetCategoryForItem(object item);

        /// <summary>
        /// Gets the full list of categories for the given items.
        /// </summary>
        List<object> GetCategoryList(IEnumerable items);
    }

    /// <summary>
    /// A category provider that categorizes items based on the first character of the
    /// property named via the PropertyName property.
    /// </summary>
    public class AlphabetCategoryProvider : ICategoryProvider
    {
        Func<object, object> m_PropertyFinder;

        public AlphabetCategoryProvider(Func<object, object> PropertyFinder)
        {
            m_PropertyFinder = PropertyFinder;
        }

        public object GetCategoryForItem(object item)
        {
            object propertyValue = m_PropertyFinder(item);
            return ((string)propertyValue).Substring(0, 1).ToUpper();
        }

        public List<object> GetCategoryList(IEnumerable items)
        {
            return Enumerable.Range(0, 26)
                    .Select(index => Convert.ToChar((Convert.ToInt32('A') + index)).ToString())
                    .Cast<object>()
                    .ToList();
        }
    }

    /// <summary>
    /// Assigns items to categories based on the value of their PropertyName property.
    /// </summary>
    public class DistinctPropertyValueCategoryProvider : ICategoryProvider
    {
        Func<object, object> m_PropertyFinder;

        public DistinctPropertyValueCategoryProvider(Func<object, object> PropertyFinder)
        {
            m_PropertyFinder = PropertyFinder;
        }

        public object GetCategoryForItem(object item)
        {
            return m_PropertyFinder(item);
        }

        public List<object> GetCategoryList(IEnumerable items)
        {
            return items.Cast<object>()
                        .Select(item => GetCategoryForItem(item))
                        .Distinct()
                        .OrderBy(cat => cat)
                        .ToList();
        }
    }
}
